<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<link rev="made" href="mailto:mark.martinec@ijs.si">
<title>
snprintf.c - a portable implementation of snprintf
(including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf)
</title>
<meta http-equiv="Content-Language" content="en">
<meta name="author"    content="Mark Martinec">
<meta name="copyright" content="Copyright 2000 Mark Martinec, All Rights Reserved">
<meta name="date"      content="2000-10-18">
<meta name="keywords" lang="en"
 content="snprintf,portable,vsnprintf,asnprintf,vasnprintf,asprintf,vasprintf
          ISO/IEC 9899:1999,ISO C99,ISO C9x,POSIX">
<style type="text/css">
<!--
  body { background: white; color: black }
 -->
</style>
</head>
<body>
<h1><b>snprintf.c</b>
<br> - a portable implementation of snprintf,
<br><font size="+1">including
vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf</font>
</h1>

<p><b>snprintf</b> is a routine to convert numeric and string arguments
to formatted strings. It is similar to sprintf(3) provided in a
system's C library, yet it requires an additional argument - the buffer
size - and it guarantees never to store anything beyond the given buffer,
regardless of the format or arguments to be formatted. Some newer
operating systems do provide <b>snprintf</b> in their C library,
but many do not or do provide an inadequate (slow or idiosyncratic)
version, which calls for a portable implementation of this routine.

<h2>Author</h2>

<p><a href="http://www.ijs.si/people/mark/">Mark Martinec</a>
&lt;<a href="mailto:mark.martinec@ijs.si">mark.martinec@ijs.si</a>&gt;,
April 1999, June 2000
<br>Copyright &copy; 1999, Mark Martinec

<h2>Terms and conditions ...</h2>

<p>This program is free software; you can redistribute it
and/or modify it under the terms of the
<i><a href="./LICENSE.txt">Frontier Artistic License</a></i>
which comes with this Kit.

<h2>Features</h2>

<ul>
<li>careful adherence to specs regarding flags, field width and precision;
<li>good performance for large string handling (large format, large argument
or large paddings). Performance is similar to system's <b>sprintf</b>
and in several cases significantly better (make sure you compile with
optimizations turned on, tell the compiler the code is strict ANSI
if necessary to give it more freedom for optimizations);
<li>return value semantics per ISO/IEC 9899:1999 ("ISO C99");
<li>written in standard ISO/ANSI C - requires an ANSI C compiler.
</ul>

<h2>Supported conversion specifiers and data types</h2>

<p>This <b>snprintf</b> only supports the following conversion specifiers:
s, c, d, o, u, x, X, p  (and synonyms: i, D, U, O - see below)
with flags: '-', '+', '&nbsp;', '0' and '#'.
An asterisk is supported for field width as well as precision.

<p>Length modifiers 'h' (<i>short int</i>), 'l' (<i>long int</i>),
and 'll' (<i>long long int</i>) are supported.

<p>NOTE:
<blockquote>
If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default)
the length modifier 'll' is recognized but treated the same as 'l',
which may cause argument value truncation!
Defining SNPRINTF_LONGLONG_SUPPORT requires that your system's
<b>sprintf</b> also handles length modifier 'll'.
<i>long long int</i> is a language extension which may not be portable.
</blockquote>

<p>Conversion of numeric data (conversion specifiers d, o, u, x, X, p)
with length modifiers (none or h, l, ll) is left to the system
routine <b>sprintf</b>, but all handling of flags, field width and precision
as well as c and s conversions is done very carefully by this portable routine.
If a string precision (truncation) is specified (e.g. %.8s) it is
guaranteed the string beyond the specified precision will not be referenced.

<p>Length modifiers h, l and ll are ignored for c and s conversions
(data types <i>wint_t</i> and <i>wchar_t</i> are not supported).

<p>The following common synonyms for conversion characters are supported:
<ul>
<li>i is a synonym for d
<li>D is a synonym for ld, explicit length modifiers are ignored
<li>U is a synonym for lu, explicit length modifiers are ignored
<li>O is a synonym for lo, explicit length modifiers are ignored
</ul>
The D, O and U conversion characters are nonstandard, they are supported
for backward compatibility only, and should not be used for new code.

<p>The following is specifically <b>not</b> supported:
<ul>
<li>flag ' (thousands' grouping character) is recognized but ignored
<li>numeric conversion specifiers: f, e, E, g, G and synonym F,
as well as the new a and A conversion specifiers
<li>length modifier 'L' (<i>long double</i>)
and 'q' (<i>quad</i> - use 'll' instead)
<li>wide character/string conversions: lc, ls, and nonstandard
synonyms C and S
<li>writeback of converted string length: conversion character n
<li>the n$ specification for direct reference to n-th argument
<li>locales
</ul>

<p>It is permitted for str_m to be zero, and it is permitted to specify NULL
pointer for resulting string argument if str_m is zero (as per ISO C99).

<p>The return value is the number of characters which would be generated
for the given input, <i>excluding</i> the trailing null. If this value
is greater or equal to str_m, not all characters from the result
have been stored in str, output bytes beyond the (str_m-1) -th character
are discarded. If str_m is greater than zero it is guaranteed
the resulting string will be null-terminated.

<p>NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
but is different from some older and vendor implementations,
and is also different from XPG, XSH5, SUSv2 specifications.
For historical discussion on changes in the semantics and standards
of snprintf see printf(3) man page in the Linux programmers manual.

<p>Routines asprintf and vasprintf return a pointer (in the ptr argument)
to a buffer sufficiently large to hold the resulting string. This pointer
should be passed to free(3) to release the allocated storage when it is
no longer needed. If sufficient space cannot be allocated, these functions
will return -1 and set ptr to be a NULL pointer. These two routines are a
GNU C library extensions (glibc).

<p>Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
characters into the allocated output string, the last character in the
allocated buffer then gets the terminating null. If the formatted string
length (the return value) is greater than or equal to the str_m argument,
the resulting string was truncated and some of the formatted characters
were discarded. These routines present a handy way to limit the amount
of allocated memory to some sane value.

<h2>Availability</h2>

<p><a href="http://www.ijs.si/software/snprintf/"
>http://www.ijs.si/software/snprintf/</a>

<ul>
<li>
<a href="./snprintf_1.3.tar.gz">snprintf_1.3.tar.gz</a> (1999-06-30),
md5 sum: <a href="./snprintf_1.3.tar.gz.md5">snprintf_1.3.tar.gz.md5</a>

<li>
<a href="./snprintf_2.1.tar.gz">snprintf_2.1.tar.gz</a> (2000-07-14),
md5 sum: <a href="./snprintf_2.1.tar.gz.md5">snprintf_2.1.tar.gz.md5</a>

<li>
<a href="./snprintf_2.2.tar.gz">snprintf_2.2.tar.gz</a> (2000-10-18),
md5 sum: <a href="./snprintf_2.2.tar.gz.md5">snprintf_2.2.tar.gz.md5</a>
</ul>


<h2>Mailing list</h2>

<p>There is a very low-traffic mailing list <i>snprintf-announce@ijs.si</i>
where announcements about new versions will be posted
as well as warnings about threatening bugs if discovered.
The posting is restricted to snprintf developer(s).

<p>To subscribe to (or unsubscribe from) the mailing list
please visit the list server's web page
<a href="http://mailman.ijs.si/listinfo/snprintf-announce"
>http://mailman.ijs.si/listinfo/snprintf-announce</a>

<p>You can also subscribe to the list by mailing
the command SUBSCRIBE either in the subject or in the message body
to the address <a href="mailto:snprintf-announce-request@ijs.si"
>snprintf-announce-request@ijs.si</a> . You will be asked for
confirmation before subscription will be effective.

<p>The list of members is only accessible to the list administrator,
so there is no need for concern about automatic e-mail address gatherers.

<p>Questions about the mailing list and concerns for the attention
of a person should be sent to <a href="mailto:snprintf-announce-admin@ijs.si"
>snprintf-announce-admin@ijs.si</a>

<p>There is no <i>general</i> discussion list about portable snprintf
at the moment. Please send comments and suggestion to the author.


<h2>Revision history</h2>

<p><b>Version 1.3 fixes a runaway loop problem from 1.2. Please upgrade.</b>

<dl>
<dt>1999-06-30	V1.3  Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li>fixed runaway loop (eventually crashing when str_l wraps
  beyond 2^31) while copying format string without
  conversion specifiers to a buffer that is too short
  (thanks to Edwin Young &lt;edwiny@autonomy.com&gt; for spotting the problem);
<li>added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) to snprintf.h
</ul>

<dt>2000-02-14	V2.0 (never released) Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li>relaxed license terms:
  <a href="./LICENSE.txt">The Artistic License</a> now applies.
  You may still apply the GNU GENERAL PUBLIC LICENSE
  as was distributed with previous versions, if you prefer;
<li>changed REVISION HISTORY dates to use
  <a href="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">ISO 8601
  date format</a>;
<li>added vsnprintf (patch also independently proposed by
  Caol&aacute;n McNamara 2000-05-04, and Keith M Willenson 2000-06-01)
</ul>

<dt>2000-06-27	V2.1  Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li>removed POSIX check for str_m &lt; 1; value 0 for str_m is
  allowed by ISO C99 (and GNU C library 2.1) (pointed out
  on 2000-05-04 by Caol&aacute;n McNamara, caolan@ csn dot ul dot ie).
  Besides relaxed license this change in standards adherence
  is the main reason to bump up the major version number;
<li>added nonstandard routines asnprintf, vasnprintf, asprintf,
  vasprintf that dynamically allocate storage for the
  resulting string; these routines are not compiled by default,
  see comments where NEED_V?ASN?PRINTF macros are defined;
<li>autoconf contributed by Caol&aacute;n McNamara
</ul>

<dt>2000-10-06	V2.2  Mark Martinec &lt;mark.martinec@ijs.si&gt;
<dd><ul>
<li><b>BUG FIX</b>: the %c conversion used a temporary variable
  that was no longer in scope when referenced,
  possibly causing incorrect resulting character;
<li>BUG FIX: make precision and minimal field width unsigned
  to handle huge values (2^31 &lt;= n &lt; 2^32) correctly;
  also be more careful in the use of signed/unsigned/size_t
  internal variables -- probably more careful than many
  vendor implementations, but there may still be a case
  where huge values of str_m, precision or minimal field
  could cause incorrect behaviour;
<li>use separate variables for signed/unsigned arguments,
  and for short/int, long, and long long argument lengths
  to avoid possible incompatibilities on certain
  computer architectures. Also use separate variable
  arg_sign to hold sign of a numeric argument,
  to make code more transparent;
<li>some fiddling with zero padding and "0x" to make it
  Linux compatible;
<li>systematically use macros fast_memcpy and fast_memset
  instead of case-by-case hand optimization; determine some
  breakeven string lengths for different architectures;
<li>terminology change: <i>format</i> -&gt; <i>conversion specifier</i>,
  <i>C9x</i> -&gt; <i>ISO/IEC 9899:1999 ("ISO C99")</i>,
  <i>alternative form</i> -&gt; <i>alternate form</i>,
  <i>data type modifier</i> -&gt; <i>length modifier</i>;
<li>several comments rephrased and new ones added;
<li>make compiler not complain about 'credits' defined but
  not used;
</ul>
</dl>

<h2>Other implementations of snprintf</h2>

<p>I am aware of some other (more or less) portable implementations
of <b>snprintf</b>. I do not claim they are free software - please refer
to their respective copyright and licensing terms.
If you know of other versions please let
<a href="http://www.ijs.si/people/mark/">me</a> know.

<ul>
<li>a very thorough implementation (src/util_snprintf.c)
by the Apache Group distributed with the
<a href="http://www.apache.org/">Apache web server
- http://www.apache.org/</a> .
Does its own floating point conversions using routines
ecvt(3), fcvt(3) and gcvt(3) from the standard C library
or from the GNU libc.

<br>This is from the code:
<blockquote>
This software [...] was originally based
on public domain software written at the
<a href="http://www.ncsa.uiuc.edu/ncsa.html">National Center
for Supercomputing Applications</a>, University of Illinois,
Urbana-Champaign.<br>
[...] This code is based on, and used with the permission of,
the SIO stdio-replacement strx_* functions by Panos Tsirigotis
&lt;<a href="mailto:panos@alumni.cs.colorado.edu">panos@alumni.cs.colorado.edu</a>&gt; for xinetd.
</blockquote>

<li><a href="http://www.qlue.com/downloads/c_utils_README.html">QCI
Utilities</a> use a modified version of snprintf from the Apache group.

<li>implementations as distributed with
<a href="http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/">OpenBSD</a>,
<a href="http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdio/">FreeBSD</a>, and
<a href="http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/basesrc/lib/libc/stdio/">NetBSD</a>
are all wrappers to vfprintf.c, which is derived from software
contributed to Berkeley by Chris Torek.

<li>implementation from Prof. Patrick Powell
&lt;<a href="mailto:papowell@sdsu.edu">papowell@sdsu.edu</a>&gt;,
Dept. Electrical and Computer Engineering, San Diego State University,
San Diego, CA 92182-1309, published in
<a href="http://www.geek-girl.com/bugtraq/1995_3/0217.html">Bugtraq
archives for 3rd quarter (Jul-Aug) 1995</a>.
No floating point conversions.

<li>Brandon Long's
&lt;<a href="mailto:blong@fiction.net">blong@fiction.net</a>&gt;
<a href="http://www.fiction.net/~blong/programs/">modified version</a>
of Prof. Patrick Powell's snprintf with contributions from others.
With minimal floating point support.

<li>implementation (src/snprintf.c) as distributed with
<a href="http://www.sendmail.org/">sendmail - http://www.sendmail.org/</a>
is a cleaned up Prof. Patrick Powell's version
to compile properly and to support .precision and %lx.

<li>implementation from <a href="http://www.csn.ul.ie/~caolan/"
>Caol&aacute;n McNamara</a> available at
<a href="http://www.csn.ul.ie/~caolan/publink/snprintf-1.1.tar.gz"
>http://www.csn.ul.ie/~caolan/publink/snprintf-1.1.tar.gz</a>,
handles floating point.

<li>implementation used by
<a href="ftp://ftp.soscorp.com/pub/sos/lib">newlog</a>
(a replacement for syslog(3)) made available by
the <a href="http://www.soscorp.com">SOS Corporation</a>.
Enabling floating point support is a compile-time option.

<li>implementation by Michael Richardson
&lt;<a href="mailto:mcr@metis.milkyway.com">mcr@metis.milkyway.com</a>&gt;
is available at
<a href="http://sandelman.ottawa.on.ca/SSW/snp/snp.html"
>http://sandelman.ottawa.on.ca/SSW/snp/snp.html</a>.
It is based on BSD44-lite's vfprintf() call, modified to function
on SunOS. Needs internal routines from the 4.4 strtod (included),
requires GCC to compile the long long (aka quad_t) portions. 

<li>implementation from Tomi Salo
&lt;<a href="mailto:ttsalo@ssh.fi">ttsalo@ssh.fi</a>&gt;
distributed with
<a href="http://www.Europe.DataFellows.com/f-secure/ssh/">SSH 2.0
Unix Server</a>. Not in public domain.
Floating point conversions done by system's sprintf.

<li>and for completeness: <a href="http://www.ijs.si/people/mark/">my</a>
portable version described in this very document available at
<a href="http://www.ijs.si/software/snprintf/"
>http://www.ijs.si/software/snprintf/</a> .
</ul>

In retrospect, it appears that a lot of effort was wasted by many
people for not being aware of what others are doing. Sigh.

<p>Also of interest:
<a href="http://www.opengroup.org/platform/resolutions/bwg98-006.html"
>The Approved Base Working Group Resolution for XSH5,
Ref: bwg98-006, Topic: snprintf</a>.

<p><hr> 
<i><a href="http://www.ijs.si/people/mark/">mm</a></i>
<br>Last updated: 2000-10-18

<p><a href="http://validator.w3.org/check/referer"
><img src="/images/vh40.gif" alt="Valid HTML 4.0!"
  border="0" width="88" height="31"></a>
</body>
</html>
